import utility
import SecLogin
import MyOptionParser
import os, time, datetime, optparse, getpass
    
class PromptInterface:
    """ This is an example class to handle authentications. Drives the hardenned password system from a shell prompt.
        Systems can be initialized or loaded, new users can be added and authenticated."""

    def __init__(self, max_tries):
        self.sec_login = None

        try:
            self.max_tries = abs(int(max_tries))
            if (self.max_tries < 1):
                raise ValueError
        except ValueError:
            utility.debug('Number of attempts allowed is incorrect.')
            return None         

    #Private functions: handle commands issued.

    """
    Command parser functions. Usage of commands described in output of help command.
    Parameters:
    args: the list of the arguments passed to the command.

    Returns: True if command other than exit executed (messages during execution are sent to stdout/stderr by inner functionality).
             False if exit command executed.

    """

    #init [--len_history|-l] l [--dir|-d] d
    def _parse_init(self, args):
        utility.debug('Init a new system. Save config file.')        

        usage = "init [--len_history|-l] len [--dir|-d] dir [--min|-m] min_len [--max|-M] max_len"
        p = MyOptionParser.MyOptionParser(usage)

        p.add_option('--len_history', '-l', type="int", default = 0)
        p.add_option('--directory', '-d', type="string", default = None)
        p.add_option('--min', '-m', type="int", default = 0)
        p.add_option('--max', '-M', type="int", default = 0)

        try:
            options, arguments = p.parse_args(args)
        except NameError:
            utility.debug('Command parsing failed, not executed.')
            return False

        if (options.directory == None):
            utility.debug('Invalid directory path.')
            return

        #SecLogin inforces minimum length, this only enforces they are  logical values.
        if (options.min < 1 or options.max < 1 or options.min > options.max):
            utility.debug('Invalid password length bounds.')
            return False
        
        self.sec_login = SecLogin.SecLogin(options.directory, options.min, options.max, options.len_history)        
        if (self.sec_login == None):
            utility.debug('System initialization failed.')
            return False
        return True
    
    def _parse_load(self, args):        
        utility.debug('Load a system from config file.')

        usage = "init [--dir|-d] d"
        p = MyOptionParser.MyOptionParser(usage)

        p.add_option('--directory', '-d', type="string", default = None)        

        try:
            options, arguments = p.parse_args(args)
        except NameError:
            utility.debug('Command parsing failed, not executed.')
            return False

        if (options.directory == None):
            utility.debug('Invalid directory path.')
            return False

        self.sec_login = SecLogin.SecLogin(options.directory)
        if (self.sec_login == None):
            utility.debug('System initialization failed.')
            return False
        return True
    
    #add -u username
    def _parse_add(self, args):
        
        if (self.sec_login == None):
            utility.debug('System uninitialized.')
            utility.message('Adding user failed.')
            return False

        usage = "add [--user|-u] username"
        p = MyOptionParser.MyOptionParser(usage)

        p.add_option('--user', '-u', type="string", default = None)        

        try:
            options, arguments = p.parse_args(args)
        except NameError:
            utility.debug('Command parsing failed, not executed.')
            utility.message('Adding user failed.')
            return False

        if (options.user == None):
            utility.debug('Invalid username.')
            utility.message('Adding user failed.')
            return False

        #Prompt for password twice.
        tries = 0
        while (tries < self.max_tries):
            pwd = getpass.getpass('Enter new password for user:')
            pwd_check = getpass.getpass('Renter new password for user:')

            if (pwd != pwd_check):
                utility.debug('Passwords did not match.')
                tries = tries + 1
                if (tries == self.max_tries):
                    utility.debug('Maximum number of attempts exceeded. Try again later.')
                    utility.message('Adding user failed.')
                    return False
            else:   
                break

        #add user                
        if ((self.sec_login.new_user(options.user, pwd)) == False):
            utility.message('Adding user failed.')
            return False
        else:
            utility.message('User successfuly added.')
            return True

    #login -u username
    def _parse_login(self, args):
        if (self.sec_login == None):
            utility.debug('System uninitialized.')
            return False

        usage = "login [--user|-u] username"
        p = MyOptionParser.MyOptionParser(usage)

        p.add_option('--user', '-u', type="string", default = None)        

        try:
            options, arguments = p.parse_args(args)
        except NameError:
            utility.debug('Command parsing failed, not executed.')
            utility.message('Login Failed.')
            return        

        if (options.user == None):
            utility.debug('Invalid username.')
            utility.message('Login Failed.')
            return        

        #Prompt for password.
        tries = 0
        while (tries < self.max_tries):
            pwd = getpass.getpass('Enter password for user:')

            if ((self.sec_login.login_user(options.user, pwd)) == False):
                utility.message('Login Failed. Try Again.')
                tries = tries + 1
                if (tries == self.max_tries):
                    utility.debug('Maximum number of attempts exceeded. Try again later.')
                    utility.message('Login Failed')
                    return False
            else:
                utility.message('Login Successful.')
                break        
        return True

    def _parse_command(self, args):
        #do a split and determine command, then pass the rest to the appropriate parser    
        command = args[0].lower()

        if command in ("init", "i"):
            if (len(args) != 9):
                utility.debug('Arguments missing')
                return True
            else:        
                if (self._parse_init(args) == False):
                    utility.message('Init Failed.')
                else:
                    utility.message('Init Successful.')
            return True

        #Load the system
        if command in ("load"):
            if (len(args) != 3):
                utility.debug('Arguments missing')
                return True
            else:        
                if (self._parse_load(args) == False):
                    utility.message('Load Failed.')
                else:
                    utility.message('Load Successful.')
            return True

        #Add a new user
        elif command in ("add", "a"):
            if (len(args) != 3):
                utility.debug('Arguments missing')
                return True
            else:        
                self._parse_add(args)
            return True

        #Login as a user
        elif command in ("login", "l"):
            if (len(args) != 3):
                utility.debug('Arguments missing')
                return True
            else:        
                self._parse_login(args)
            return True

        elif command in ("help", "h"):
            utility.message('''
Printing options
  init [--len_history|-l] len [--dir|-d] dir [--min|-m] min_len [--max|-M] max_len initialize the system, with history_file size h(integer) and base directory d (string: fully qualified path) and minimum password lengt min_len and maximum password length max_len
  load [--dir|-d] d: initialize the system by loading it from the config file, found at the base directory d (string: fully qualified path)
  add [--user|-u] username: add a new user with login name \'username\' .
  login [--user|-u] username: authenticate the user with login name \'username\' .
  exit: quit the program.
  help: print this help menu.
            ''')
            return True

        elif command in ("exit", "e"):
            return False

        else:
            utility.debug('No such command as %s. Try help!' % command)
            return True
    
    #Public functions 
    """
    Execute commands issued on prompt until user issues exit command.
    Parameters: None.
    Returns: nNone
    """
    def handle(self):
        while(1):
            string = raw_input('$')
            command = string.split()
            if len(command) == 0:
                utility.debug('Specify a command! Type help to see possibilities')
                continue
            #parses arguments, calls appropriate command parser
            elif (not self._parse_command(command)):
                break
        return

#Insert unit test here for verifying module implementation
if __name__ == "__main__":
    print 'Unit Test PromptInterface'
    pIF = PromptInterface(2)
    pIF.handle()
    
